package org.xbdframework.jdbc.core;

import java.lang.reflect.Array;

import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.jdbc.core.namedparam.SqlParameterSource;

public class SqlAndParam<T> {

	private static final Pattern PARAMETER_PATTERN_MAP = Pattern
			.compile(":([a-zA-Z_][a-zA-Z0-9_\\.]*)");

	private static final Pattern PARAMETER_PATTERN_ARRAY = Pattern.compile("\\?");

	private final Logger logger = LoggerFactory.getLogger(SqlAndParam.class);

	private final String sql;

	private final T param;

	public SqlAndParam(String sql, T param) {
		this.sql = sql;
		this.param = param;
	}

	public String getSql() {
		if (this.param == null) {
			return this.sql;
		}

		StringBuffer sb = new StringBuffer();

		try {
			Matcher e;
			if (this.param instanceof Map) {
				e = PARAMETER_PATTERN_MAP.matcher(this.sql);
				while (e.find()) {
					if (((Map<?, ?>) this.param).containsKey(e.group(1))) {
						String value = SqlParameterValueUtils
								.getValue(((Map<?, ?>) this.param).get(e.group(1)));
						e.appendReplacement(sb, Matcher.quoteReplacement(value));
					}
					else {
						e.appendReplacement(sb, e.group());
					}
				}

				e.appendTail(sb);
				return sb.toString();
			}
			else if (this.param.getClass().isArray()) {
				e = PARAMETER_PATTERN_ARRAY.matcher(this.sql);
				int i = 0;

				while (e.find()) {
					String value = SqlParameterValueUtils
							.getValue(Array.get(this.param, i++));
					e.appendReplacement(sb, Matcher.quoteReplacement(value));
				}

				e.appendTail(sb);
				return sb.toString();
			}
			else if (this.param instanceof SqlParameterSource) {
				e = PARAMETER_PATTERN_MAP.matcher(this.sql);
				while (e.find()) {
					if (((SqlParameterSource) this.param).hasValue(e.group(1))) {
						String value = SqlParameterValueUtils.getValue(
								((SqlParameterSource) this.param).getValue(e.group(1)));
						e.appendReplacement(sb, Matcher.quoteReplacement(value));
					}
					else {
						e.appendReplacement(sb, e.group());
					}
				}

				e.appendTail(sb);
				return sb.toString();
			}
			else {
				sb.append(this.sql);
			}
		}
		catch (Exception e) {
			logger.error(e.getMessage(), e);
			sb.append(this.toString());
		}

		return sb.toString();
	}

	public String getOriginalSql() {
		return this.sql;
	}

	public T getParam() {
		return this.param;
	}

	public static void main(String[] args) {
		Map<String, Object> paramMap = new HashMap<>();
		paramMap.put("id", "21212121");

		String sql = "select * from e_api_user where id = :id";
		SqlAndParam<Map<String, Object>> sb = new SqlAndParam<>(sql, paramMap);
		System.out.println(sb.getSql());

		Object[] ids = { 2, 3 };
		paramMap.put("ids", ids);

		sql = "select * from e_api_user where id1 = :id1 and id in (:ids)";
		sb = new SqlAndParam<>(sql, paramMap);
		System.out.println(sb.getSql());

		Object[] names = { "张三", "李四" };
		paramMap.put("names", names);

		sql = "select * from e_api_user where name in (:names)";
		sb = new SqlAndParam<>(sql, paramMap);
		System.out.println(sb.getSql());
	}

}
